package com.kool.kreport.service;

import com.kool.kreport.bean.*;
import com.kool.kreport.client.RedisClient;
import com.kool.kreport.common.util.DateUtil;
import com.kool.kreport.constant.DateDimEnum;
import com.kool.kreport.constant.PacketTypeEnum;
import com.kool.kreport.dao.*;
import com.kool.kreport.vo.TopicFilterClientCountVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author luyu
 */
@Service
@Slf4j
public class DailyReportService {
    @Resource
    private ReportGlobalPacketCountDao globalPacketCountDao;
    @Resource
    private ReportGlobalReceiveCostDao globalReceiveCostDao;
    @Resource
    private ReportGlobalSessionCountDao globalSessionCountDao;
    @Resource
    private ReportGlobalNoAckCountDao globalNoAckCountDao;
    @Resource
    private ReportClientNoAckCountDao clientNoAckCountDao;
    @Resource
    private SubscriptionSnapshotDao subscriptionSnapshotDao;
    @Resource
    private ReportGlobalSubscribeCountDao globalSubscribeCountDao;
    @Resource
    private ReportGlobalTopicPublishCountDao globalTopicPublishCountDao;
    @Resource
    private ReportUserPacketCountDao userPacketCountDao;
    @Resource
    private ReportClientPacketCountDao clientPacketCountDao;
    @Resource
    private ReportAddressPacketCountDao addressPacketCountDao;

    @Resource
    private RedisClient redisClient;

    /**
     * 参数1：日期
     * 参数2：报文类型 {@link com.kool.kreport.constant.PacketTypeEnum}
     * 参数3：global/user_name/client_id/remote_address
     * 参数4：global/用户名/客户端ID/客户端地址
     */
    public static final String KEY_TODAY_RECEIVE_SUCCESS = "kmetrics:today_receive_success:%s:%s:%s:%s";
    public static final String KEY_TODAY_RECEIVE_FAIL = "kmetrics:today_receive_fail:%s:%s:%s:%s";
    public static final String KEY_TODAY_RECEIVE_TOTAL = "kmetrics:today_receive_total:%s:%s:%s:%s";
    public static final String KEY_TODAY_RECEIVE_COST_AVG = "kmetrics:today_receive_cost_avg:%s:%s:%s:%s";
    public static final String KEY_TODAY_RECEIVE_COST_MAX = "kmetrics:today_receive_cost_max:%s:%s:%s:%s";
    /**
     * 参数1：日期
     * 参数2：报文类型 {@link com.kool.kreport.constant.PacketTypeEnum}
     * 参数3：global/user_name/client_id/remote_address
     * 参数4：global/用户名/客户端ID/客户端地址
     */
    public static final String KEY_TODAY_SEND_SUCCESS = "kmetrics:today_send_success:%s:%s:%s:%s";
    public static final String KEY_TODAY_SEND_FAIL = "kmetrics:today_send_fail:%s:%s:%s:%s";
    public static final String KEY_TODAY_SEND_TOTAL = "kmetrics:today_send_total:%s:%s:%s:%s";
    /**
     * 参数1：分钟，yyyyMMddHHmm
     */
    private static final String KEY_SESSION_CNT = "kmetrics:session_cnt:%s";
    /**
     * 参数1：日期
     * 参数2：主题名
     * 参数3：global/user_name/client_id/remote_address
     * 参数4：global/用户名/客户端ID/客户端地址
     */
    public static final String KEY_TODAY_TOPIC_RECEIVE_SUCCESS = "kmetrics:today_topic_receive_success:%s:%s:%s:%s";
    /**
     * 参数1：日期
     * 参数2：主题名
     * 参数3：global/user_name/client_id/remote_address
     * 参数4：global/用户名/客户端ID/客户端地址
     */
    public static final String KEY_TODAY_TOPIC_SEND_SUCCESS = "kmetrics:today_topic_send_success:%s:%s:%s:%s";

    /**
     * hash结构
     * 参数1：日期
     * hkey：topicName
     * hvalue:空
     */
    public static final String KEY_TODAY_TOPIC = "kmetrics:today_topic:%s";
    /**
     * hash结构
     * 参数1：日期
     * hkey：userName
     * hvalue:空
     */
    public static final String KEY_TODAY_USER = "kmetrics:today_user:%s";
    /**
     * hash结构
     * 参数1：日期
     * hkey：clientId
     * hvalue:空
     */
    public static final String KEY_TODAY_CLIENT_ID = "kmetrics:today_client_id:%s";
    /**
     * hash结构
     * 参数1：日期
     * hkey：remoteAddress
     * hvalue:空
     */
    public static final String KEY_TODAY_REMOTE_ADDRESS = "kmetrics:today_remote_address:%s";

    /**
     * 计算日报表
     *
     * @param day
     * @param isUpdate
     */
    public void computeDailyReport(int day, boolean isUpdate) {
        try {
            //计算平台入站出站报文流量报表
            log.info("计算平台入站出站报文流量报表");
            computeGlobalPacketCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台入站出站报文流量报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算平台入站耗时报表
            log.info("计算平台入站耗时报表");
            computeGlobalCost(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台入站耗时报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算平台会话数报表
            log.info("计算平台会话数报表");
            computeGlobalSessionCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台会话数报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算平台出站未确认报文数报表
            log.info("计算平台出站未确认报文数报表");
            computeGlobalNoAckCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台出站未确认报文数报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算平台订阅量报表
            log.info("计算平台订阅量报表");
            computeGlobalSubscriptionCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台订阅量报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算平台主题流量报表
            log.info("计算平台主题流量报表");
            computeGlobalTopicPublishCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算平台主题流量报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算用户流量报表
            log.info("计算用户流量报表");
            computeUserPacketCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算用户流量报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算客户端流量报表
            log.info("计算客户端流量报表");
            computeClientPacketCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算客户端流量报表异常！");
            log.error(e.getMessage(), e);
        }

        try {
            //计算客户端地址流量报表
            log.info("计算客户端地址流量报表");
            computeRemoteAddressPacketCount(day, isUpdate);
        } catch (Exception e) {
            log.error("计算客户端地址流量报表异常！");
            log.error(e.getMessage(), e);
        }

    }

    /**
     * 计算平台入站出站报文流量报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalPacketCount(int day, boolean isUpdate) {
        //查询当日报表是否已存在
        ReportGlobalPacketCountDo condition = new ReportGlobalPacketCountDo();
        condition.setReportDate(day);
        int rows = globalPacketCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台入站出站报文流量日报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalPacketCountDao.deleteByDate(day);
        }

        List<ReportGlobalPacketCountDo> globalPacketCountDos = new ArrayList<>();
        for (PacketTypeEnum packetTypeEnum : PacketTypeEnum.values()) {
            String receiveSuccess = redisClient.get(String.format(KEY_TODAY_RECEIVE_SUCCESS, day, packetTypeEnum.getCode(), "global"));
            String receiveFail = redisClient.get(String.format(KEY_TODAY_RECEIVE_FAIL, day, packetTypeEnum.getCode(), "global", "global"));
            String receiveTotal = redisClient.get(String.format(KEY_TODAY_RECEIVE_TOTAL, day, packetTypeEnum.getCode(), "global", "global"));
            String sendSuccess = redisClient.get(String.format(KEY_TODAY_SEND_SUCCESS, day, packetTypeEnum.getCode(), "global", "global"));
            String sendFail = redisClient.get(String.format(KEY_TODAY_SEND_FAIL, day, packetTypeEnum.getCode(), "global", "global"));
            String sendTotal = redisClient.get(String.format(KEY_TODAY_SEND_TOTAL, day, packetTypeEnum.getCode(), "global", "global"));

            ReportGlobalPacketCountDo globalPacketCountDo = new ReportGlobalPacketCountDo();
            globalPacketCountDo.setDateDim(DateDimEnum.Day.getCode())
                    .setReportDate(day)
                    .setPacketType(packetTypeEnum.getCode())
                    .setReceiveSuccess(Long.parseLong(Optional.ofNullable(receiveSuccess).orElse("0")))
                    .setReceiveFail(Long.parseLong(Optional.ofNullable(receiveFail).orElse("0")))
                    .setReceiveTotal(Long.parseLong(Optional.ofNullable(receiveTotal).orElse("0")))
                    .setSendSuccess(Long.parseLong(Optional.ofNullable(sendSuccess).orElse("0")))
                    .setSendFail(Long.parseLong(Optional.ofNullable(sendFail).orElse("0")))
                    .setSendTotal(Long.parseLong(Optional.ofNullable(sendTotal).orElse("0")));

            globalPacketCountDos.add(globalPacketCountDo);
        }

        globalPacketCountDao.batchInsert(globalPacketCountDos);
    }

    /**
     * 计算平台入站耗时报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalCost(int day, boolean isUpdate) {
        ReportGlobalReceiveCostDo condition = new ReportGlobalReceiveCostDo();
        condition.setReportDate(day);
        int rows = globalReceiveCostDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台入站耗时报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalReceiveCostDao.deleteByDate(day);
        }
        List<ReportGlobalReceiveCostDo> globalReceiveCostDos = new ArrayList<>();
        for (PacketTypeEnum packetTypeEnum : PacketTypeEnum.values()) {
            String avgCost = redisClient.get(String.format(KEY_TODAY_RECEIVE_COST_AVG, day, packetTypeEnum.getCode(), "global", "global"));
            String maxCost = redisClient.get(String.format(KEY_TODAY_RECEIVE_COST_MAX, day, packetTypeEnum.getCode(), "global", "global"));

            ReportGlobalReceiveCostDo globalReceiveCostDo = new ReportGlobalReceiveCostDo();
            globalReceiveCostDo.setDateDim(DateDimEnum.Day.getCode())
                    .setReportDate(day)
                    .setPacketType(packetTypeEnum.getCode())
                    .setAvgCost(Long.parseLong(Optional.ofNullable(avgCost).orElse("0")))
                    .setMaxCost(Long.parseLong(Optional.ofNullable(maxCost).orElse("0")));

            globalReceiveCostDos.add(globalReceiveCostDo);
        }

        globalReceiveCostDao.batchInsert(globalReceiveCostDos);

    }

    /**
     * 计算平台会话数报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalSessionCount(int day, boolean isUpdate) {
        ReportGlobalSessionCountDo condition = new ReportGlobalSessionCountDo();
        condition.setReportDate(day);
        int rows = globalSessionCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台会话数报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalSessionCountDao.deleteByDate(day);
        }

        long sum = 0L;
        long max = 0L;
        Date from = DateUtil.toDateDay(day);
        for (int i = 0; i < 1440; i++) {
            Date minute = DateUtil.getMinuteAfter(from, i);
            String cntString = redisClient.get(String.format(KEY_SESSION_CNT, DateUtil.dateString(minute, "yyyyMMddHHmm")));
            long cnt = Long.parseLong(Optional.ofNullable(cntString).orElse("0"));
            sum += cnt;
            if (cnt > max) {
                max = cnt;
            }
        }
        ReportGlobalSessionCountDo globalSessionCountDo = new ReportGlobalSessionCountDo();
        globalSessionCountDo.setDateDim(DateDimEnum.Day.getCode())
                .setReportDate(day)
                .setAvgCnt(sum / 1440L)
                .setMaxCnt(max);
        globalSessionCountDao.insert(globalSessionCountDo);
    }

    /**
     * 计算平台出站未确认报文数报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalNoAckCount(int day, boolean isUpdate) {
        ReportGlobalNoAckCountDo condition = new ReportGlobalNoAckCountDo();
        condition.setReportDate(day);
        int rows = globalNoAckCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台出站未确认报文数报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalNoAckCountDao.deleteByDate(day);
        }

        ReportClientNoAckCountDo groupClientNoAck = clientNoAckCountDao.groupGlobalCount(day);

        ReportGlobalNoAckCountDo globalNoAckCountDo = new ReportGlobalNoAckCountDo();
        globalNoAckCountDo.setDateDim(DateDimEnum.Day.getCode())
                .setReportDate(day)
                .setAvgCnt(groupClientNoAck.getAvgCnt())
                .setMaxCnt(groupClientNoAck.getMaxCnt());

        globalNoAckCountDao.insert(globalNoAckCountDo);
    }

    /**
     * 计算平台订阅量报表
     * 主题过滤器的客户端数
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalSubscriptionCount(int day, boolean isUpdate) {
        ReportGlobalSubscribeCountDo condition = new ReportGlobalSubscribeCountDo();
        condition.setReportDate(day);
        int rows = globalSubscribeCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台订阅量报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalSubscribeCountDao.deleteByDate(day);
        }

        Date dateFrom = DateUtil.toDateDay(day);
        Date dateTo = DateUtil.getDateAfter(dateFrom, 1);
        List<TopicFilterClientCountVo> groupTopicFilterCnts = subscriptionSnapshotDao.groupTopicFilterCount(dateFrom, dateTo);

        List<ReportGlobalSubscribeCountDo> globalSubscribeCountDos = new ArrayList<>();
        for (TopicFilterClientCountVo topicFilterClientCountVo : groupTopicFilterCnts) {
            ReportGlobalSubscribeCountDo globalSubscribeCountDo = new ReportGlobalSubscribeCountDo();
            globalSubscribeCountDo.setDateDim(DateDimEnum.Day.getCode())
                    .setReportDate(day)
                    .setTopicFilter(topicFilterClientCountVo.getTopicFilter())
                    .setClientCnt(topicFilterClientCountVo.getCnt());

            globalSubscribeCountDos.add(globalSubscribeCountDo);
        }

        globalSubscribeCountDao.batchInsert(globalSubscribeCountDos);
    }

    /**
     * 计算平台主题流量报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeGlobalTopicPublishCount(int day, boolean isUpdate) {
        ReportGlobalTopicPublishCountDo condition = new ReportGlobalTopicPublishCountDo();
        condition.setReportDate(day);
        int rows = globalTopicPublishCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}平台主题流量报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            globalTopicPublishCountDao.deleteByDate(day);
        }

        HashMap<String, ReportGlobalTopicPublishCountDo> globalTopicPublishCntMap = new HashMap<>();
        //查询当日的主题
        Map<String, String> topicNames = redisClient.hgetMap(String.format(KEY_TODAY_TOPIC, day));
        if (topicNames != null) {
            for (String topicName : topicNames.keySet()) {
                //入站数
                String receiveCnt = redisClient.get(String.format(KEY_TODAY_TOPIC_RECEIVE_SUCCESS, day, topicName, "global", "global"));

                //出站数
                String sendCnt = redisClient.get(String.format(KEY_TODAY_TOPIC_SEND_SUCCESS, day, topicName, "global", "global"));
                ReportGlobalTopicPublishCountDo globalTopicPublishCountDo = globalTopicPublishCntMap.getOrDefault(topicName, new ReportGlobalTopicPublishCountDo());
                globalTopicPublishCountDo.setDateDim(DateDimEnum.Day.getCode())
                        .setReportDate(day)
                        .setTopicName(topicName)
                        .setReceiveSuccess(Long.parseLong(Optional.ofNullable(receiveCnt).orElse("0")))
                        .setSendSuccess(Long.parseLong(Optional.ofNullable(sendCnt).orElse("0")));

                globalTopicPublishCntMap.put(topicName, globalTopicPublishCountDo);
            }
        }

        List<ReportGlobalTopicPublishCountDo> globalTopicPublishCountDos = new ArrayList<>(globalTopicPublishCntMap.values());
        globalTopicPublishCountDao.batchInsert(globalTopicPublishCountDos);
    }

    /**
     * 计算用户流量报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeUserPacketCount(int day, boolean isUpdate) {
        ReportUserPacketCountDo condition = new ReportUserPacketCountDo();
        condition.setReportDate(day);
        int rows = userPacketCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}用户流量报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            userPacketCountDao.deleteByDate(day);
        }
        List<ReportUserPacketCountDo> userPacketCountDos = new ArrayList<>();
        for (PacketTypeEnum packetTypeEnum : PacketTypeEnum.values()) {
            Map<String, String> userNames = redisClient.hgetMap(String.format(KEY_TODAY_USER, day));
            if (userNames != null) {
                for (String userName : userNames.keySet()) {
                    String receiveSuccess = redisClient.get(String.format(KEY_TODAY_RECEIVE_SUCCESS, day, packetTypeEnum.getCode(), "user_name", userName));
                    String receiveFail = redisClient.get(String.format(KEY_TODAY_RECEIVE_FAIL, day, packetTypeEnum.getCode(), "user_name", userName));
                    String receiveTotal = redisClient.get(String.format(KEY_TODAY_RECEIVE_TOTAL, day, packetTypeEnum.getCode(), "user_name", userName));
                    String sendSuccess = redisClient.get(String.format(KEY_TODAY_SEND_SUCCESS, day, packetTypeEnum.getCode(), "user_name", userName));
                    String sendFail = redisClient.get(String.format(KEY_TODAY_SEND_FAIL, day, packetTypeEnum.getCode(), "user_name", userName));
                    String sendTotal = redisClient.get(String.format(KEY_TODAY_SEND_TOTAL, day, packetTypeEnum.getCode(), "user_name", userName));

                    ReportUserPacketCountDo userPacketCountDo = new ReportUserPacketCountDo();
                    userPacketCountDo.setDateDim(DateDimEnum.Day.getCode())
                            .setReportDate(day)
                            .setPacketType(packetTypeEnum.getCode())
                            .setUserName(userName)
                            .setReceiveSuccess(Long.parseLong(Optional.ofNullable(receiveSuccess).orElse("0")))
                            .setReceiveFail(Long.parseLong(Optional.ofNullable(receiveFail).orElse("0")))
                            .setReceiveTotal(Long.parseLong(Optional.ofNullable(receiveTotal).orElse("0")))
                            .setSendSuccess(Long.parseLong(Optional.ofNullable(sendSuccess).orElse("0")))
                            .setSendFail(Long.parseLong(Optional.ofNullable(sendFail).orElse("0")))
                            .setSendTotal(Long.parseLong(Optional.ofNullable(sendTotal).orElse("0")));

                    userPacketCountDos.add(userPacketCountDo);
                }
            }
        }
        userPacketCountDao.batchInsert(userPacketCountDos);
    }

    /**
     * 计算客户端流量报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeClientPacketCount(int day, boolean isUpdate) {
        ReportClientPacketCountDo condition = new ReportClientPacketCountDo();
        condition.setReportDate(day);
        int rows = clientPacketCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}客户端流量报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            clientPacketCountDao.deleteByDate(day);
        }
        List<ReportClientPacketCountDo> clientPacketCountDos = new ArrayList<>();
        for (PacketTypeEnum packetTypeEnum : PacketTypeEnum.values()) {
            Map<String, String> clientIds = redisClient.hgetMap(String.format(KEY_TODAY_CLIENT_ID, day));
            if (clientIds != null) {
                for (String clientId : clientIds.keySet()) {
                    String receiveSuccess = redisClient.get(String.format(KEY_TODAY_RECEIVE_SUCCESS, day, packetTypeEnum.getCode(), "client_id", clientId));
                    String receiveFail = redisClient.get(String.format(KEY_TODAY_RECEIVE_FAIL, day, packetTypeEnum.getCode(), "client_id", clientId));
                    String receiveTotal = redisClient.get(String.format(KEY_TODAY_RECEIVE_TOTAL, day, packetTypeEnum.getCode(), "client_id", clientId));
                    String sendSuccess = redisClient.get(String.format(KEY_TODAY_SEND_SUCCESS, day, packetTypeEnum.getCode(), "client_id", clientId));
                    String sendFail = redisClient.get(String.format(KEY_TODAY_SEND_FAIL, day, packetTypeEnum.getCode(), "client_id", clientId));
                    String sendTotal = redisClient.get(String.format(KEY_TODAY_SEND_TOTAL, day, packetTypeEnum.getCode(), "client_id", clientId));

                    ReportClientPacketCountDo clientPacketCountDo = new ReportClientPacketCountDo();
                    clientPacketCountDo.setDateDim(DateDimEnum.Day.getCode())
                            .setReportDate(day)
                            .setPacketType(packetTypeEnum.getCode())
                            .setClientId(clientId)
                            .setReceiveSuccess(Long.parseLong(Optional.ofNullable(receiveSuccess).orElse("0")))
                            .setReceiveFail(Long.parseLong(Optional.ofNullable(receiveFail).orElse("0")))
                            .setReceiveTotal(Long.parseLong(Optional.ofNullable(receiveTotal).orElse("0")))
                            .setSendSuccess(Long.parseLong(Optional.ofNullable(sendSuccess).orElse("0")))
                            .setSendFail(Long.parseLong(Optional.ofNullable(sendFail).orElse("0")))
                            .setSendTotal(Long.parseLong(Optional.ofNullable(sendTotal).orElse("0")));

                    clientPacketCountDos.add(clientPacketCountDo);
                }
            }
        }
        clientPacketCountDao.batchInsert(clientPacketCountDos);
    }

    /**
     * 计算客户端地址流量报表
     *
     * @param day
     * @param isUpdate
     */
    private void computeRemoteAddressPacketCount(int day, boolean isUpdate) {
        ReportAddressPacketCountDo condition = new ReportAddressPacketCountDo();
        condition.setReportDate(day);
        int rows = addressPacketCountDao.countTotal(condition);
        if (rows > 0 && !isUpdate) {
            //如果已存在且不允许覆盖，则返回
            log.info("{}客户端地址流量报表已存在，不覆盖", day);
            return;
        } else if (rows > 0 && isUpdate) {
            //如果已存在且允许覆盖，则删除
            addressPacketCountDao.deleteByDate(day);
        }
        List<ReportAddressPacketCountDo> addressPacketCountDos = new ArrayList<>();
        for (PacketTypeEnum packetTypeEnum : PacketTypeEnum.values()) {
            Map<String, String> remoteAddresses = redisClient.hgetMap(String.format(KEY_TODAY_REMOTE_ADDRESS, day));
            if (remoteAddresses != null) {
                for (String remoteAddress : remoteAddresses.keySet()) {
                    String receiveSuccess = redisClient.get(String.format(KEY_TODAY_RECEIVE_SUCCESS, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));
                    String receiveFail = redisClient.get(String.format(KEY_TODAY_RECEIVE_FAIL, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));
                    String receiveTotal = redisClient.get(String.format(KEY_TODAY_RECEIVE_TOTAL, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));
                    String sendSuccess = redisClient.get(String.format(KEY_TODAY_SEND_SUCCESS, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));
                    String sendFail = redisClient.get(String.format(KEY_TODAY_SEND_FAIL, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));
                    String sendTotal = redisClient.get(String.format(KEY_TODAY_SEND_TOTAL, day, packetTypeEnum.getCode(), "remote_address", remoteAddress));

                    ReportAddressPacketCountDo addressPacketCountDo = new ReportAddressPacketCountDo();
                    addressPacketCountDo.setDateDim(DateDimEnum.Day.getCode())
                            .setReportDate(day)
                            .setPacketType(packetTypeEnum.getCode())
                            .setRemoteAddress(remoteAddress)
                            .setReceiveSuccess(Long.parseLong(Optional.ofNullable(receiveSuccess).orElse("0")))
                            .setReceiveFail(Long.parseLong(Optional.ofNullable(receiveFail).orElse("0")))
                            .setReceiveTotal(Long.parseLong(Optional.ofNullable(receiveTotal).orElse("0")))
                            .setSendSuccess(Long.parseLong(Optional.ofNullable(sendSuccess).orElse("0")))
                            .setSendFail(Long.parseLong(Optional.ofNullable(sendFail).orElse("0")))
                            .setSendTotal(Long.parseLong(Optional.ofNullable(sendTotal).orElse("0")));

                    addressPacketCountDos.add(addressPacketCountDo);
                }
            }
        }
        addressPacketCountDao.batchInsert(addressPacketCountDos);
    }
}
